#include "myopenglwidget.h"
#include "myopenglwidget.moc" // 确保这个宏在这里被处理


// 相对于每个坐标轴的旋转角度（°）
enum { Xaxis, Yaxis, Zaxis, NumAxes };
int Axis = Xaxis;
//float   Theta[NumAxes] = { 0.0, 0.0, 0.0 };
//QVector3D   Theta = { 20.0, -10.0, 0.0 };
QVector3D Theta = {-80.0, 0.0, 220.0};
QVector3D ViewPos = {0.0, -0.5, 0};
QVector3D Scale = {1.0, 1.0, 1.0};
//QVector3D   Theta;
/*
    QVector3D rotate = QVector3D(-90.0,0.0,180.0);
    QVector3D scale = QVector3D(1.0,1.0,1.0);
    QVector3D viewpos = QVector3D(0.0,-0.5,2.0);
*/

#define FACTOR 80.0
bool rotateFlag = false;
bool scaleFlag = false;
bool viewPosFlag = false;

MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    shaderProgram = new QOpenGLShaderProgram();
    vAO = new QOpenGLVertexArrayObject();
    vBO = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    eBO = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);

    connect(&m_tm, SIGNAL(timeout()), this, SLOT(slotTimeout()));
    //m_tm.start(1);

    OpenGLWidgetRunThread* openGLWidgetRunThread = new OpenGLWidgetRunThread();
    openGLWidgetRunThread->SetMyOpenGLWidget(this);
    openGLWidgetRunThread->start();
}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    // 从obj文件中读取数据
    std::string warn;
    std::string err;
    QDir dir;
    QString pathname = dir.absoluteFilePath("d:/seat3.obj");
    bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, "d:/seat3.obj");

    if (!warn.empty()) {
        qDebug() << "WARN: " << warn;
    }

    if (!err.empty()) {
        qDebug() << "ERR: " << err;
    }

    if (!ret) {
        printf("Failed to load/parse .obj.\n");
    }

    nCount = shapes[0].mesh.indices.size();

    GLfloat *vertices = (GLfloat *) malloc(2 * attrib.GetVertices().size() * sizeof(GLfloat));
    unsigned int *indices = (unsigned int *) malloc(shapes[0].mesh.indices.size()
                                                    * sizeof(unsigned int));

    QVector<GLfloat> vertData;
    QVector<GLfloat> normalData;
    QVector<unsigned int> indicesData;

    for (int i = 0; i < attrib.GetVertices().size(); i++) {
        vertData.append(attrib.vertices.at(i));
        normalData.append(attrib.normals.at(i));
    }

    for (int i = 0; i < attrib.GetVertices().size() / 3; i++) {
        vertices[6 * i + 0] = vertData.at(3 * i + 0) / FACTOR;
        vertices[6 * i + 1] = vertData.at(3 * i + 1) / FACTOR;
        vertices[6 * i + 2] = vertData.at(3 * i + 2) / FACTOR;
        vertices[6 * i + 3] = normalData.at(3 * i + 0);
        vertices[6 * i + 4] = normalData.at(3 * i + 1);
        vertices[6 * i + 5] = normalData.at(3 * i + 2);
    }

    for (int i = 0; i < shapes[0].mesh.indices.size(); i++) {
        indicesData.append(shapes[0].mesh.indices.at(i).vertex_index);
        indices[i] = shapes[0].mesh.indices.at(i).vertex_index;
    }

    // VAO
    vAO->create();
    vAO->bind();
    // VBO
    vBO->create();
    vBO->bind();
    vBO->allocate(vertices, 2 * vertData.size() * sizeof(GLfloat));
    // EBO
    eBO->create();
    eBO->bind();
    eBO->allocate(indices, indicesData.size() * sizeof(unsigned int));

    shaderProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,
                                                    ":/res/res/shader/shader1.vert");
    shaderProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,
                                                    ":/res/res/shader/shader1.frag");
    shaderProgram->link();

    shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
    shaderProgram->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
    shaderProgram->enableAttributeArray(0);
    shaderProgram->enableAttributeArray(1);

    vBO->release();
    vAO->release();

    delete vertices;
    delete indices;

    glEnable(GL_DEPTH_TEST);
}

void MyOpenGLWidget::resizeGL(int w, int h) {}

void MyOpenGLWidget::paintGL()
{
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QVector3D lightColor(1.0f, 1.0f, 1.0f);
    QVector3D objectColor(0.4f, 0.4f, 0.4f);
    QVector3D objectPos(0.0f, 0.0f, -3.0f);
    QVector3D lightSourcePos(0, 10.0f, 10.0f);
    float ambientStrength = 0.1f;
    float specularStrength = 0.1f;

    // ---------------------------------
    // // 绘制 物体
    QMatrix4x4 translateModel;
    translateModel.translate(objectPos);

    QMatrix4x4 rx, ry, rz;
    rx.rotate(Theta[Xaxis], 1.0, 0.0, 0.0);
    ry.rotate(Theta[Yaxis], 0.0, 1.0, 0.0);
    rz.rotate(Theta[Zaxis], 0.0, 0.0, 1.0);

    QMatrix4x4 scaleModel;
    scaleModel.scale(Scale);

    QMatrix4x4 model = translateModel * rx * ry * rz * scaleModel;

    QMatrix4x4 view;
    view.setColumn(3, QVector4D(ViewPos, 1));

    QMatrix4x4 projection;
    projection.perspective(30.0f, (float) width() / height(), 0.1f, 100.0f);

    shaderProgram->setUniformValue("model", model);
    shaderProgram->setUniformValue("view", view);
    shaderProgram->setUniformValue("projection", projection);

    shaderProgram->setUniformValue("lightColor", lightColor);
    shaderProgram->setUniformValue("objectColor", objectColor);
    shaderProgram->setUniformValue("lightPos", lightSourcePos);

    shaderProgram->setUniformValue("ambientStrength", ambientStrength);
    shaderProgram->setUniformValue("specularStrength", specularStrength);
    shaderProgram->setUniformValue("lighting", true);
    //shaderProgram->setUniformValue ("viewPos", QVector3D(0,0,3) );

    shaderProgram->bind();
    vAO->bind();
    glDrawElements(GL_TRIANGLES, nCount, GL_UNSIGNED_INT, 0);
}

void MyOpenGLWidget::Run3DModel(){
    bool redraw = rotateFlag || viewPosFlag || scaleFlag;

    //每过一定时间，增加一定值
    if (rotateFlag) {
        if (qAbs(Theta[Xaxis] - destinationAngles.x()) > 0.5) {
            if (Theta[Xaxis] < destinationAngles.x())
                Theta[Xaxis] += 1;
            else
                Theta[Xaxis] -= 1;

            if (Theta[Xaxis] > 360.0)
                Theta[Xaxis] = -360.0;
        } else if (qAbs(Theta[Yaxis]-destinationAngles.y()) > 0.5) {
            if (Theta[Yaxis] < destinationAngles.y())
                Theta[Yaxis] += 1;
            else
                Theta[Yaxis] -= 1;

            if (Theta[Yaxis] > 360.0)
                Theta[Yaxis] = -360.0;
        } else if (qAbs(Theta[Zaxis] - destinationAngles.z()) > 0.5) {
            if (Theta[Zaxis] < destinationAngles.z())
                Theta[Zaxis] += 1;
            else
                Theta[Zaxis] -= 1;

            if (Theta[Zaxis] > 360.0)
                Theta[Zaxis] = -360.0;
        } else {
            rotateFlag = false;
        }
    }

    if (scaleFlag) {
        if (qAbs(Scale[Xaxis] - destinationScales.x()) > 0.05) {
            if (Scale[Xaxis] < destinationScales.x())
                Scale[Xaxis] += 0.01;
            else
                Scale[Xaxis] -= 0.01;
        } else if (qAbs(Scale[Yaxis] - destinationScales.y()) > 0.05) {
            if (Scale[Yaxis] < destinationScales.x())
                Scale[Yaxis] += 0.01;
            else
                Scale[Yaxis] -= 0.01;
        } else if (qAbs(Scale[Zaxis] - destinationScales.z()) > 0.05) {
            if (Scale[Zaxis] < destinationScales.x())
                Scale[Zaxis] += 0.01;
            else
                Scale[Zaxis] -= 0.01;
        } else {
            scaleFlag = false;
        }
    }

    if (viewPosFlag) {
        if (qAbs(ViewPos[Xaxis] - destinationViewPos.x()) > 0.05) {
            if (ViewPos[Xaxis] < destinationViewPos.x())
                ViewPos[Xaxis] += 0.01;
            else
                ViewPos[Xaxis] -= 0.01;
        } else if (qAbs(ViewPos[Yaxis] - destinationViewPos.y()) > 0.05) {
            if (ViewPos[Yaxis] < destinationViewPos.y())
                ViewPos[Yaxis] += 0.01;
            else
                ViewPos[Yaxis] -= 0.01;
        } else if (qAbs(ViewPos[Zaxis] - destinationViewPos.z()) > 0.05) {
            if (ViewPos[Zaxis] < destinationViewPos.z())
                ViewPos[Zaxis] += 0.01;
            else
                ViewPos[Zaxis] -= 0.01;
        } else {
            viewPosFlag = false;
        }
    }

    if (redraw) {
        update();
    }
}

void MyOpenGLWidget::slotTimeout()
{
    bool redraw = rotateFlag || viewPosFlag || scaleFlag;

    //每过一定时间，增加一定值
    if (rotateFlag) {
        if (qAbs(Theta[Xaxis] - destinationAngles.x()) > 0.5) {
            if (Theta[Xaxis] < destinationAngles.x())
                Theta[Xaxis] += 1;
            else
                Theta[Xaxis] -= 1;

            if (Theta[Xaxis] > 360.0)
                Theta[Xaxis] = -360.0;
        } else if (qAbs(Theta[Yaxis]-destinationAngles.y()) > 0.5) {
            if (Theta[Yaxis] < destinationAngles.y())
                Theta[Yaxis] += 1;
            else
                Theta[Yaxis] -= 1;

            if (Theta[Yaxis] > 360.0)
                Theta[Yaxis] = -360.0;
        } else if (qAbs(Theta[Zaxis] - destinationAngles.z()) > 0.5) {
            if (Theta[Zaxis] < destinationAngles.z())
                Theta[Zaxis] += 1;
            else
                Theta[Zaxis] -= 1;

            if (Theta[Zaxis] > 360.0)
                Theta[Zaxis] = -360.0;
        } else {
            rotateFlag = false;
        }
    }

    if (scaleFlag) {
        if (qAbs(Scale[Xaxis] - destinationScales.x()) > 0.05) {
            if (Scale[Xaxis] < destinationScales.x())
                Scale[Xaxis] += 0.01;
            else
                Scale[Xaxis] -= 0.01;
        } else if (qAbs(Scale[Yaxis] - destinationScales.y()) > 0.05) {
            if (Scale[Yaxis] < destinationScales.x())
                Scale[Yaxis] += 0.01;
            else
                Scale[Yaxis] -= 0.01;
        } else if (qAbs(Scale[Zaxis] - destinationScales.z()) > 0.05) {
            if (Scale[Zaxis] < destinationScales.x())
                Scale[Zaxis] += 0.01;
            else
                Scale[Zaxis] -= 0.01;
        } else {
            scaleFlag = false;
        }
    }

    if (viewPosFlag) {
        if (qAbs(ViewPos[Xaxis] - destinationViewPos.x()) > 0.05) {
            if (ViewPos[Xaxis] < destinationViewPos.x())
                ViewPos[Xaxis] += 0.01;
            else
                ViewPos[Xaxis] -= 0.01;
        } else if (qAbs(ViewPos[Yaxis] - destinationViewPos.y()) > 0.05) {
            if (ViewPos[Yaxis] < destinationViewPos.y())
                ViewPos[Yaxis] += 0.01;
            else
                ViewPos[Yaxis] -= 0.01;
        } else if (qAbs(ViewPos[Zaxis] - destinationViewPos.z()) > 0.05) {
            if (ViewPos[Zaxis] < destinationViewPos.z())
                ViewPos[Zaxis] += 0.01;
            else
                ViewPos[Zaxis] -= 0.01;
        } else {
            viewPosFlag = false;
        }
    }

    if (redraw) {
        update();
    }
}

void MyOpenGLWidget::controlMessage(QVector3D angles, QVector3D scale, QVector3D viewPos)
{
    if (destinationAngles != angles) {
        destinationAngles = angles;
        rotateFlag = true;
    }

    if (destinationScales != scale) {
        destinationScales = scale;
        scaleFlag = true;
    }

    if (destinationViewPos != viewPos) {
        destinationViewPos = viewPos;
        viewPosFlag = true;
    }
}
